ποΈGitΠ―ΡΠ°ποΈ
.skills/testing-ci/SKILL.md d4eadee500c39e2e09f352a385ee7f3b2bd1a79f (d4eadee5) Text, 6.70 KB
Skill: Testing and CI Verification
Description
Guidelines and commands for verifying code changes locally and understanding the Meshtastic-Android CI pipeline. Use this to determine which testing matrix is needed based on the change type.
1) Baseline local verification order
Run in a single invocation for routine changes to ensure code formatting, analysis, and basic compilation:
T282828
./gradlew spotlessCheck spotlessApply detekt assembleDebug Tffa657test allTests
β Why no T383838clean? Incremental builds are safe and significantly faster. Only use T383838clean when debugging
β stale cache issues.
β Why T383838test allTests and not just T383838test: In KMP modules, the T383838test task name is ambiguous. Gradle
β matches both T383838testAndroid and T383838testAndroidHostTest and refuses to run either, silently skipping KMP
β modules. T383838allTests is the T383838KotlinTestReport lifecycle task registered by the KMP plugin.
β Conversely, T383838allTests does not cover pure-Android modules (T383838:app, T383838:core:api, etc.), which is why
β both T383838test and T383838allTests are needed.
Note: If testing Compose UI on the JVM (Robolectric) with Java 21, pin tests to T383838@Config(sdk = [34]) to avoid SDK 35 compatibility crashes.
2) Change-type verification matrix
β’ T383838docs-only changes: Usually no Gradle run required, but run T383838spotlessCheck if practical.
β’ T383838UI text/resource changes: T383838spotlessCheck, T383838detekt, T383838assembleDebug.
β’ T383838feature/commonMain logic changes: T383838spotlessCheck, T383838detekt, T383838test allTests, T383838assembleDebug.
β’ T383838navigation/DI wiring changes: T383838spotlessCheck, T383838detekt, T383838assembleDebug, T383838test allTests, plus flavor unit tests if available.
β’ If touching any KMP module, also run T383838kmpSmokeCompile.
β’ T383838worker/service/background changes: Broad tests, targeted WorkManager checks.
β’ T383838BLE/networking/core repository: T383838spotlessCheck, T383838detekt, T383838assembleDebug, T383838test allTests.
3) Flavor checks
Run these when relevant to map, provider, or flavor-specific behavior:
T282828
./gradlew lintFdroidDebug lintGoogleDebug
./gradlew testFdroidDebug testGoogleDebug
4) CI Pipeline Architecture
CI is defined in T383838.github/workflows/reusable-check.yml and structured as four parallel job groups:
1. T383838lint-check β Runs spotless, detekt, Android lint, and KMP smoke compile in a single Gradle invocation (avoids 3x cold-start overhead). Uses T383838fetch-depth: 0 (full clone) for spotless ratcheting and version code calculation. Produces T383838cache_read_only output and computed T383838version_code for downstream jobs.
2. T383838test-shards β A 3-shard matrix that runs unit tests in parallel (depends on T383838lint-check):
β’ T383838shard-core: T383838allTests for all T383838core:* KMP modules.
β’ T383838shard-feature: T383838allTests for all T383838feature:* KMP modules.
β’ T383838shard-app: Explicit test tasks for pure-Android/JVM modules (T383838app, T383838desktop, T383838core:barcode).
Each shard generates Kover XML coverage and uploads test results + coverage to Codecov with per-shard flags.
Downstream jobs use T383838fetch-depth: 1 and receive T383838VERSION_CODE from lint-check via env var, enabling shallow clones.
3. T383838android-check β Builds APKs for all flavors (depends on T383838lint-check).
4. T383838build-desktop β Multi-OS matrix (T383838macos-latest, T383838windows-latest, T383838ubuntu-24.04, T383838ubuntu-24.04-arm) that builds desktop distributions via T383838createDistributable (depends on T383838lint-check).
Runner Strategy (Three Tiers)
β’ T383838ubuntu-24.04-arm β Lightweight/utility jobs (status checks, labelers, triage, changelog, release metadata, stale, moderation). Benefits from ARM runners' shorter queue times.
β’ T383838ubuntu-24.04 β Main Gradle-heavy jobs (CI T383838lint-check/T383838test-shards/T383838android-check, release builds, Dokka, publish, dependency-submission). Pin for reproducibility.
β’ Desktop runners: Multi-OS matrix (T383838macos-latest, T383838windows-latest, T383838ubuntu-24.04, T383838ubuntu-24.04-arm) for the T383838build-desktop job and release packaging.
CI Gradle Properties
T383838gradle.properties is tuned for local dev (8g heap, 4g Kotlin daemon). CI uses T383838.github/ci-gradle.properties, which the T383838gradle-setup composite action copies to T383838~/.gradle/gradle.properties. Key CI overrides:
β’ T383838org.gradle.daemon=false (single-use runners)
β’ T383838kotlin.incremental=false (fresh checkouts)
β’ T383838-Xmx4g Gradle heap, T383838-Xmx2g Kotlin daemon
β’ VFS watching disabled, workers capped at 4
β’ T383838org.gradle.isolated-projects=true for better parallelism
β’ Disables unused Android build features (T383838resvalues, T383838shaders)
CI Conventions
β’ KMP Smoke Compile: T383838./gradlew kmpSmokeCompile is a lifecycle task (registered in T383838RootConventionPlugin) that auto-discovers all KMP modules and depends on their T383838compileKotlinJvm + T383838compileKotlinIosSimulatorArm64 tasks.
β’ T383838maxParallelForks CI logic: T383838ProjectExtensions.kt checks T383838project.findProperty("ci") == "true" and uses full available processors in CI (4 forks on std runners) vs. half locally. All CI invocations pass T383838-Pci=true.
β’ Detekt report formats: Detekt.kt checks T383838project.findProperty("ci") == "true" and disables html, txt, md reports in CI; only xml + sarif are retained for GitHub annotations.
β’ Robolectric SDK caching: The T383838gradle-setup composite action caches T383838~/.m2/repository/org/robolectric to prevent flaky T383838SocketException on SDK downloads. Cache key is T383838robolectric-{version}-sdk{level} β update when bumping version or SDK level.
β’ T383838mavenLocal() gated: Disabled by default to prevent CI cache poisoning. Pass T383838-PuseMavenLocal for local JitPack testing.
β’ JUnit parallel execution: Enabled project-wide with classes running sequentially (T383838junit.jupiter.execution.parallel.mode.classes.default=same_thread) to avoid T383838Dispatchers.setMain() races. Cross-module parallelism comes from Gradle forks (T383838maxParallelForks).
β’ T383838test-retry plugin: Applied to all module types (maxRetries=2, maxFailures=10).
β’ T383838fail-fast: false: Test sharding does not cancel other shards on failure.
β’ Explicit Gradle task paths: Prefer T383838app:lintFdroidDebug over shorthand T383838lintDebug in CI.
β’ Pull request CI: Main-only (T383838.github/workflows/pull-request.yml targets T383838main).
β’ Cache writes: Trusted on T383838main and merge queue runs; other refs use read-only cache.
β’ Path filtering: T383838check-changes in T383838pull-request.yml must include module dirs plus build/workflow entrypoints (T383838build-logic/**, T383838gradle/**, T383838.github/workflows/**, T383838gradlew, T383838settings.gradle.kts, etc.).
β’ AboutLibraries: Runs in T383838offlineMode by default (no GitHub/SPDX API calls). Release builds pass T383838-PaboutLibraries.release=true via Fastlane/Gradle CLI to enable remote license fetching. Do NOT re-gate on T383838CI or T383838GITHUB_TOKEN alone.
Served by rngit 1.5.4 - Generated in 0.03s